package com.zhangtao.demo.config.redis.jedis;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.zhangtao.demo.common.util.ByteUtil;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.zhangtao.demo.common.constant.JedisConstant;
import com.zhangtao.demo.common.dto.Holder;

import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.Tuple;
import redis.clients.util.Slowlog;

@Component
public class JedisApi {

	@Autowired
	private RedisPool rpool;
	private static final Logger logger = LogManager.getLogger(JedisApi.class);

	/**
	 * 
	 * @Title: select
	 * @Description: 切换数据库
	 * @param: @param db
	 * @param: @return
	 * @return: boolean
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:29:23
	 */
	public boolean select(int db) {
		return rpool.setCurrentDb(db);
	}

	/**
	 * 
	 * @Title: changeHost
	 * @Description: 切换redis host信息
	 * @param: @param host
	 * @param: @param port
	 * @param: @param pass
	 * @param: @param db
	 * @param: @return
	 * @return: boolean
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:30:02
	 */
	public boolean changeHost(String host, int port, String pass, int db) {
		if (StringUtils.isBlank(host)) {
			return false;
		}
		if (port < 0) {
			return false;
		}
		if (db < 0 || db > 15) {
			return false;
		}
		return rpool.changeRedisPool(host, port, pass, db);
	}

	/**
	 * 
	 * @Title: info
	 * @Description: 查看redis服务器的相关信息
	 * @param: @param section
	 * @param: @return
	 * @return: String
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:31:35
	 */
	public String info(String section) {
		Holder<String> holder = new Holder<>();
		rpool.execute(j -> {
			String s = null;
			if (StringUtils.isBlank(section)) {
				s = j.info();
			} else {
				s = j.info(section);
			}
//			logger.info("info {} : [{}]", section, s);
			holder.value(s);
		});
		return holder.value();
	}
	/**
	 * int到byte[] 由高位到低位
	 * @param i 需要转换为byte数组的整行值。
	 * @return byte数组
	 */
	public byte[] intToByteArray(int i) {
		byte[] result = new byte[4];
		result[0] = (byte) ((i >> 24) & 0xFF);
		result[1] = (byte) ((i >> 16) & 0xFF);
		result[2] = (byte) ((i >> 8) & 0xFF);
		result[3] = (byte) (i & 0xFF);
		return result;
	}
	private final char HexCharArr[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

	private final String HexStr = "0123456789abcdef";

	public String byteArrToHex(byte[] btArr) {
		char strArr[] = new char[btArr.length * 2];
		int i = 0;
		for (byte bt : btArr) {
			strArr[i++] = HexCharArr[bt>>>4 & 0xf];
			strArr[i++] = HexCharArr[bt & 0xf];
		}
		return new String(strArr);
	}
	/**
	 *
	 * @Title: scanKey
	 * @Description: 查询key
	 * @param: @param start
	 * @param: @param count
	 * @param: @param pattern
	 * @param: @return
	 * @return: ScanResult<String>
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:32:29
	 */
	public ScanResult<String> scanN(int start, int count, final String pattern) {
		Holder<ScanResult<String>> holder = new Holder<>();
		rpool.execute(j -> {
			ScanParams sp = new ScanParams();
			sp.count(count);
			sp.match(pattern);
			ScanResult<String> result = j.scan(String.valueOf(start), sp);
			while ((result.getResult() == null || result.getResult().size() == 0)
					&& !"0".equals(result.getStringCursor())) {
				result = j.scan(result.getStringCursor(), sp);
			}
			holder.value(result);
		});
		return holder.value();
	}
	/**
	 * 
	 * @Title: scanKey
	 * @Description: 查询key
	 * @param: @param start
	 * @param: @param count
	 * @param: @param pattern
	 * @param: @return
	 * @return: ScanResult<String>
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:32:29
	 */
	public ScanResult<String> scan(int start, int count, final String pattern) {
		Holder<ScanResult<String>> holder = new Holder<ScanResult<String>>();
		rpool.execute(j -> {
			ScanParams sp = new ScanParams();
			sp.count(count);
			sp.match(pattern);
			ScanResult<String> result = j.scan(String.valueOf(start), sp);
//			ScanResult<byte[]> byteResult = j.scan(intToByteArray(start), sp);
//			List<String> nresultList = new ArrayList<>(byteResult.getResult().size());
//			byteResult.getResult().forEach(b -> {
//				System.out.println("-----------------byte data ---------------");
//				String deCodeData = "";
//				JdkSerializationRedisSerializer jrs = new JdkSerializationRedisSerializer();
//				try {
//					Object deserialStr = jrs.deserialize(b);
//					System.out.println(ByteUtil.bytesToString(b));
//					System.out.println(ByteUtil.byteToHex(b));
////					System.out.println(byteArrToHex(deserialStr.toString().getBytes()));
//				} catch (Exception e) {
//					deCodeData = new String(b);
//				}
//				nresultList.add(deCodeData);
//			});
			while ((result.getResult() == null || result.getResult().size() == 0)
					&& !"0".equals(result.getStringCursor())) {
				result = j.scan(result.getStringCursor(), sp);
			}
			holder.value(result);
			if (!"0".equals(result.getStringCursor()) && result.getResult().size() < count) {
				List<String> scanr = new ArrayList<>();
				scanr.addAll(result.getResult());
				ScanResult<String> nresult = j.scan(result.getStringCursor(), sp);
				resolveScanResult(scanr, nresult);
				while (!"0".equals(nresult.getStringCursor()) && scanr.size() < count) {
					nresult = j.scan(nresult.getStringCursor(), sp);
					resolveScanResult(scanr, nresult);
				}
				ScanResult<String> f = new ScanResult<>(nresult.getStringCursor(), scanr);
				holder.value(f);
			}
		});
		return holder.value();
	}
	private void resolveScanResult(List<String> data, ScanResult<String> s) {
		logger.info("scan result : {}", JSONObject.toJSONString(s));
		if (s != null && s.getResult().size() > 0) {
			data.addAll(s.getResult());
		}
	}
	public boolean hasKey(String key) {
		Holder<Boolean> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.exists(key));
			logger.info("exists {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	public String get(String key) {
		Holder<String> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.get(key));
			logger.info("get {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	public long strlen(String key) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.strlen(key));
			logger.info("strlen {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	public boolean set(String key, String value) {
		Holder<Boolean> holder = new Holder<>();
		rpool.execute(j -> {
			String r = j.set(key, value);
			holder.value(JedisConstant.RESULTCODE.equalsIgnoreCase(r));
			logger.info("set {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: del
	 * @Description: 删除指定的key
	 * @param: @param key
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:41:52
	 */
	public long del(String... keys) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.del(keys));
			// j.unlink(keys);
			logger.info("del {} : [{}]", keys, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: hScanKey
	 * @Description: 查询hash类型的field
	 * @param: @param start
	 * @param: @param count
	 * @param: @param key
	 * @param: @param pattern
	 * @param: @return
	 * @return: ScanResult<Map.Entry<String,String>>
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:32:48
	 */
	public ScanResult<Map.Entry<String, String>> hscan(int start, int count, String key, String pattern) {
		Holder<ScanResult<Map.Entry<String, String>>> holder = new Holder<>();
		rpool.execute(j -> {
			if (StringUtils.contains(pattern, "*")) {
				// 模糊查询
				logger.info("模糊查询: {}", pattern);
				ScanParams sp = new ScanParams();
				sp.count(count);
				sp.match(pattern);
				ScanResult<Map.Entry<String, String>> result = j.hscan(key, String.valueOf(start), sp);
				while ((result.getResult() == null || result.getResult().size() == 0)
						&& !"0".equals(result.getStringCursor())) {
					logger.debug("--- scan \"{}\"", result.getStringCursor());
					result = j.hscan(key, result.getStringCursor(), sp);
				}
				// logger.info("hscan {} {} match {} count {} : [{}]", key, start, pattern,
				// count,
				// JSONObject.toJSONString(result));
				holder.value(result);
			} else {
				logger.info("精确查询: \"{}\"", pattern);
				// 精确查询
				String result = j.hget(key, pattern);
				if (StringUtils.isNotBlank(result)) {
					Map<String, String> data = new HashMap<>(1);
					data.put(pattern, result);
					Map.Entry<String, String> e = data.entrySet().iterator().next();
					List<Map.Entry<String, String>> l = new ArrayList<Map.Entry<String, String>>();
					l.add(e);
					ScanResult<Map.Entry<String, String>> sr = new ScanResult<>("0", l);
					holder.value(sr);
				}
			}

		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: hlen
	 * @Description: 查看hash类型数据的field数量
	 * @param: @param key
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月30日 下午1:59:04
	 */
	public long hlen(String key) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.hlen(key));
			logger.info("hlen {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: hdel
	 * @Description: 删除hash中指定的field
	 * @param: @param key
	 * @param: @param fields
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:41:11
	 */
	public long hdel(String key, String... fields) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.hdel(key, fields));
		});
		return holder.value();
	}

	public Long hset(String key, String field, String value) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.hset(key, field, value));
			logger.info("hset {} {} {} : [{}]", key, field, value, holder.value());
		});
		return holder.value();
	}

	public String hmset(String key, Map<String, String> hash) {
		Holder<String> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.hmset(key, hash));
			logger.info("hmset {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: SScanKey
	 * @Description: 查询set类型的元素
	 * @param: @param start
	 * @param: @param count
	 * @param: @param key
	 * @param: @param pattern
	 * @param: @return
	 * @return: ScanResult<String>
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:33:07
	 */
	public ScanResult<String> sscan(int start, int count, String key, String pattern) {
		Holder<ScanResult<String>> holder = new Holder<>();
		rpool.execute(j -> {
			ScanParams sp = new ScanParams();
			sp.count(count);
			sp.match(pattern);
			ScanResult<String> result = j.sscan(key, String.valueOf(start), sp);
			while ((result.getResult() == null || result.getResult().size() == 0)
					&& !"0".equals(result.getStringCursor())) {
				result = j.sscan(key, String.valueOf(start), sp);
			}
//			logger.info("sscan {} {} match {} count {} : [{}]", key, start, pattern, count,
//					JSONObject.toJSONString(result));
			holder.value(result);
		});
		return holder.value();
	}

	public long sadd(String key, String... members) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			long result = j.sadd(key, members);
			logger.info("sadd {} {} : [{}]", key, members, result);
			holder.value(result);
		});
		return holder.value();
	}

	public List<String> lrange(String key, int start, int end) {
		Holder<List<String>> holder = new Holder<>();
		rpool.execute(j -> {
			List<String> result = j.lrange(key, start, end);
			// logger.info("lrange {} {} {} : [{}]", key, start, end,
			// JSONObject.toJSONString(result));
			holder.value(result);
		});
		return holder.value();
	}

	public long rpush(String key, String... members) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			long result = j.rpush(key, members);
			logger.info("rpush {} {} : [{}]", key, members, result);
			holder.value(result);
		});
		return holder.value();
	}

	public Set<Tuple> zrange(String key, int start, int end, boolean withScores) {
		Holder<Set<Tuple>> holder = new Holder<>();
		rpool.execute(j -> {
			Set<Tuple> result = j.zrangeWithScores(key, start, end);
			// logger.info("zrangeWithScores {} {} {} : [{}]", key, start, end,
			// JSONObject.toJSONString(result));
			holder.value(result);
		});
		return holder.value();
	}

	public Set<Tuple> zrevrange(String key, int start, int end, boolean withScores) {
		Holder<Set<Tuple>> holder = new Holder<>();
		rpool.execute(j -> {
			Set<Tuple> result = j.zrevrangeWithScores(key, start, end);
			// logger.info("zrevrangeWithScores {} {} {} : [{}]", key, start, end,
			// JSONObject.toJSONString(result));
			holder.value(result);
		});
		return holder.value();
	}

	public long zset(String key, double score, String member) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			long result = j.zadd(key, score, member);
			logger.info("zadd {} {} {} : [{}]", key, score, member, result);
			holder.value(result);
		});
		return holder.value();
	}

	public long ttl(String key) {
		if (StringUtils.isBlank(key)) {
			return -1;
		}
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			Long ttl = j.ttl(key);
			logger.info("ttl {} : [{}]", key, ttl);
			holder.value(ttl);
		});
		return holder.value();
	}

	public long llen(String key) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.llen(key));
			logger.info("llen {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: scard
	 * @Description: 查询set类型的元素数量
	 * @param: @param key
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:37:36
	 */
	public long scard(String key) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.scard(key));
			logger.info("scard {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: zcard
	 * @Description: 查询zset类型的元素数量
	 * @param: @param key
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:37:05
	 */
	public long zcard(String key) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.zcard(key));
			logger.info("zcard {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	public String keyType(String key) {
		Holder<String> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.type(key));
			logger.info("type {} : [{}]", key, holder.value());
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: srem
	 * @Description: 删除set中指定的元素
	 * @param: @param key
	 * @param: @param members
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:40:57
	 */
	public long srem(String key, String... members) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.srem(key, members));
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: zrem
	 * @Description: 删除zset中的指定元素
	 * @param: @param key
	 * @param: @param members
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年11月29日 上午10:45:34
	 */
	public long zrem(String key, String... members) {
		Holder<Long> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.zrem(key, members));
			logger.info("zrem {} {} : {}", key, members, holder.value());
		});
		return holder.value();
	}

	public long lrem(String key, int index, String member) {
		Holder<Long> holder = new Holder<>();
		Holder<String> indexM = new Holder<>();
		rpool.execute(j -> {
			String rm = j.lindex(key, index);
			indexM.value(rm);
		});
		rpool.executeMulti(t -> {
			String rm = indexM.value();
			if (StringUtils.equals(rm, member)) {
				// 由于list原生命令中没有提供删除指定元素的方法，所以这里采取另一种思路
				// 先将指定index的值替换成一个内部定义的特殊的常量字段：只有系统内部知道，外部是不知道的
				String randomStr = RandomStringUtils.random(10, true, true);
				String replaceStr = String.format("%s:%s", JedisConstant.JEDIS_LIST_REMDV, randomStr);
				t.lset(key, index, replaceStr);
				// 再将所有为这个常量字段的元素删除
				t.lrem(key, 0, replaceStr);
				List<Object> r = t.exec();
				Object result = r.stream()
						.filter(obj -> !(JedisConstant.RESULTCODE.equals(obj) || Integer.parseInt(obj.toString()) > 0))
						.findFirst().orElse(null);
				if (result == null) {
					holder.value(1L);
				} else {
					holder.value(-1L);
				}
				logger.info("lrem by index and member : {}", JSONObject.toJSONString(r));
			} else {
				logger.warn("{}[{}]:{} not match this value {}!", key, index, rm, member);
				holder.value(-1L);
			}
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: lrem
	 * @Description: 删除list中指定index的值
	 * @param: @param key
	 * @param: @param index
	 * @param: @return
	 * @return: long
	 * @throws @author 张涛
	 * @Date 2018年12月6日 上午10:06:26
	 */
	public long lrem(String key, int index) {
		Holder<Long> holder = new Holder<>();
		rpool.executeMulti(t -> {
			// 由于list原生命令中没有提供删除指定元素的方法，所以这里采取另一种思路
			// 先将指定index的值替换成一个内部定义的特殊的常量字段：只有系统内部知道，外部是不知道的
			String randomStr = RandomStringUtils.random(10, true, true);
			String replaceStr = String.format("%s:%s", JedisConstant.JEDIS_LIST_REMDV, randomStr);
			t.lset(key, index, replaceStr);
			// 再将所有为这个常量字段的元素删除
			t.lrem(key, 0, replaceStr);
			List<Object> r = t.exec();
			Object result = r.stream()
					.filter(obj -> !(JedisConstant.RESULTCODE.equals(obj) || Integer.parseInt(obj.toString()) > 0))
					.findFirst().orElse(null);
			if (result == null) {
				holder.value(1L);
			} else {
				holder.value(-1L);
			}
			logger.info("lrem by index : {}", JSONObject.toJSONString(r));
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: lset
	 * @Description: 修改指定index上的值
	 * @param: @param key
	 * @param: @param index
	 * @param: @param value
	 * @param: @return
	 * @return: boolean
	 * @throws @author 张涛
	 * @Date 2018年12月10日 上午10:05:20
	 */
	public boolean lset(String key, int index, String value) {
		Holder<Boolean> holder = new Holder<>();
		rpool.execute(j -> {
			String r = j.lset(key, index, value);
			if (JedisConstant.RESULTCODE.equalsIgnoreCase(r)) {
				holder.value(true);
			} else {
				holder.value(false);
			}
			logger.info("lset {} {} {} : {}", key, index, value, r);
		});
		return holder.value();
	}

	/**
	 * 
	 * @Title: slowlog
	 * @Description: 慢查询日志,用来分析redis中执行比较慢的命令
	 * @param: @param entryCount
	 * @param: @return
	 * @return: List<Slowlog>
	 * @throws @author 张涛
	 * @Date 2019年6月17日 下午1:18:39
	 */
	public List<Slowlog> slowlog(long entryCount) {
		Holder<List<Slowlog>> holder = new Holder<>();
		rpool.execute(j -> {
			holder.value(j.slowlogGet(entryCount));
		});
		return holder.value();
	}
}
